home *** CD-ROM | disk | FTP | other *** search
/ MacWorld 2003 August / MW 8 2003 CD1.iso / Inside Macworld / Product News / gimp-1.2.4.sit / gimp-1.2.4 / app / shear_tool.c < prev    next >
Encoding:
C/C++ Source or Header  |  2001-10-25  |  9.2 KB  |  365 lines

  1. /* The GIMP -- an image manipulation program
  2.  * Copyright (C) 1995 Spencer Kimball and Peter Mattis
  3.  *
  4.  * This program is free software; you can redistribute it and/or modify
  5.  * it under the terms of the GNU General Public License as published by
  6.  * the Free Software Foundation; either version 2 of the License, or
  7.  * (at your option) any later version.
  8.  *
  9.  * This program is distributed in the hope that it will be useful,
  10.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.  * GNU General Public License for more details.
  13.  *
  14.  * You should have received a copy of the GNU General Public License
  15.  * along with this program; if not, write to the Free Software
  16.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  17.  */
  18.  
  19. #include "config.h"
  20.  
  21. #include <stdlib.h>
  22.  
  23. #include <glib.h>
  24.  
  25. #include "apptypes.h"
  26.  
  27. #include "appenv.h"
  28. #include "drawable.h"
  29. #include "gdisplay.h"
  30. #include "gimage_mask.h"
  31. #include "info_dialog.h"
  32. #include "shear_tool.h"
  33. #include "selection.h"
  34. #include "transform_tool.h"
  35. #include "undo.h"
  36.  
  37. #include "tile_manager_pvt.h"
  38.  
  39. #include "libgimp/gimpintl.h"
  40. #include "libgimp/gimpmath.h"
  41.  
  42. /*  index into trans_info array  */
  43. #define HORZ_OR_VERT 0
  44. #define XSHEAR       1
  45. #define YSHEAR       2
  46.  
  47. /*  the minimum movement before direction of shear can be determined (pixels) */
  48. #define MIN_MOVE     5
  49.  
  50. /*  variables local to this file  */
  51. static gdouble  xshear_val;
  52. static gdouble  yshear_val;
  53.  
  54. /*  forward function declarations  */
  55. static void   shear_tool_recalc  (Tool *, void *);
  56. static void   shear_tool_motion  (Tool *, void *);
  57. static void   shear_info_update  (Tool *);
  58.  
  59. /*  Info dialog callback funtions  */
  60. static void   shear_x_mag_changed (GtkWidget *widget, gpointer data);
  61. static void   shear_y_mag_changed (GtkWidget *widget, gpointer data);
  62.  
  63. TileManager *
  64. shear_tool_transform (Tool           *tool,
  65.               gpointer        gdisp_ptr,
  66.               TransformState  state)
  67. {
  68.   TransformCore *transform_core;
  69.   GDisplay       *gdisp;
  70.  
  71.   transform_core = (TransformCore *) tool->private;
  72.   gdisp = (GDisplay *) gdisp_ptr;
  73.  
  74.   switch (state)
  75.     {
  76.     case INIT:
  77.       if (!transform_info)
  78.     {
  79.       transform_info = info_dialog_new (_("Shear Information"),
  80.                         gimp_standard_help_func,
  81.                         "tools/transform.html#TOOLS-TRANSFORM-SHEARING");
  82.  
  83.       info_dialog_add_spinbutton (transform_info,
  84.                       _("Shear Magnitude X:"),
  85.                       &xshear_val,
  86.                       -65536, 65536, 1, 15, 1, 1, 0,
  87.                       shear_x_mag_changed, tool);
  88.  
  89.       info_dialog_add_spinbutton (transform_info,
  90.                       _("Y:"),
  91.                       &yshear_val,
  92.                       -65536, 65536, 1, 15, 1, 1, 0,
  93.                       shear_y_mag_changed, tool);
  94.     }
  95.       gtk_widget_set_sensitive (GTK_WIDGET (transform_info->shell), TRUE);
  96.       transform_core->trans_info[HORZ_OR_VERT] = ORIENTATION_UNKNOWN;
  97.       transform_core->trans_info[XSHEAR] = 0.0;
  98.       transform_core->trans_info[YSHEAR] = 0.0;
  99.  
  100.       return NULL;
  101.       break;
  102.  
  103.     case MOTION:
  104.       shear_tool_motion (tool, gdisp_ptr);
  105.       shear_tool_recalc (tool, gdisp_ptr);
  106.       break;
  107.  
  108.     case RECALC:
  109.       shear_tool_recalc (tool, gdisp_ptr);
  110.       break;
  111.  
  112.     case FINISH:
  113.       gtk_widget_set_sensitive (GTK_WIDGET (transform_info->shell), FALSE);
  114.       return shear_tool_shear (gdisp->gimage,
  115.                    gimage_active_drawable (gdisp->gimage),
  116.                    gdisp,
  117.                    transform_core->original,
  118.                    transform_tool_smoothing (),
  119.                    transform_core->transform);
  120.       break;
  121.     }
  122.  
  123.   return NULL;
  124. }
  125.  
  126. Tool *
  127. tools_new_shear_tool (void)
  128. {
  129.   Tool          *tool;
  130.   TransformCore *private;
  131.  
  132.   tool = transform_core_new (SHEAR, TRUE);
  133.  
  134.   private = tool->private;
  135.  
  136.   /*  set the rotation specific transformation attributes  */
  137.   private->trans_func = shear_tool_transform;
  138.  
  139.   /*  assemble the transformation matrix  */
  140.   gimp_matrix3_identity (private->transform);
  141.  
  142.   return tool;
  143. }
  144.  
  145. void
  146. tools_free_shear_tool (Tool *tool)
  147. {
  148.   transform_core_free (tool);
  149. }
  150.  
  151. static void
  152. shear_info_update (Tool *tool)
  153. {
  154.   TransformCore *transform_core;
  155.  
  156.   transform_core = (TransformCore *) tool->private;
  157.  
  158.   xshear_val = transform_core->trans_info[XSHEAR];
  159.   yshear_val = transform_core->trans_info[YSHEAR];
  160.  
  161.   info_dialog_update (transform_info);
  162.   info_dialog_popup (transform_info);
  163. }
  164.  
  165. static void
  166. shear_x_mag_changed (GtkWidget *widget,
  167.              gpointer   data)
  168. {
  169.   Tool          *tool;
  170.   TransformCore *transform_core;
  171.   GDisplay      *gdisp;
  172.   gint           value;
  173.  
  174.   tool = (Tool *) data;
  175.  
  176.   if (tool)
  177.     {
  178.       gdisp = (GDisplay *) tool->gdisp_ptr;
  179.       transform_core = (TransformCore *) tool->private;
  180.  
  181.       value = GTK_ADJUSTMENT (widget)->value;
  182.  
  183.       if (value != transform_core->trans_info[XSHEAR])
  184.     {
  185.       draw_core_pause (transform_core->core, tool);
  186.       transform_core->trans_info[XSHEAR] = value;
  187.       shear_tool_recalc (tool, gdisp);
  188.       draw_core_resume (transform_core->core, tool);
  189.     }
  190.     }
  191. }
  192.  
  193. static void
  194. shear_y_mag_changed (GtkWidget *widget,
  195.              gpointer   data)
  196. {
  197.   Tool          *tool;
  198.   TransformCore *transform_core;
  199.   GDisplay      *gdisp;
  200.   gint           value;
  201.  
  202.   tool = (Tool *) data;
  203.  
  204.   if (tool)
  205.     {
  206.       gdisp = (GDisplay *) tool->gdisp_ptr;
  207.       transform_core = (TransformCore *) tool->private;
  208.  
  209.       value = GTK_ADJUSTMENT (widget)->value;
  210.  
  211.       if (value != transform_core->trans_info[YSHEAR])
  212.     {
  213.       draw_core_pause (transform_core->core, tool);
  214.       transform_core->trans_info[YSHEAR] = value;
  215.       shear_tool_recalc (tool, gdisp);
  216.       draw_core_resume (transform_core->core, tool);
  217.     }
  218.     }
  219. }
  220.  
  221. static void
  222. shear_tool_motion (Tool *tool,
  223.            void *gdisp_ptr)
  224. {
  225.   TransformCore *transform_core;
  226.   gint           diffx, diffy;
  227.   gint           dir;
  228.  
  229.   transform_core = (TransformCore *) tool->private;
  230.  
  231.   diffx = transform_core->curx - transform_core->lastx;
  232.   diffy = transform_core->cury - transform_core->lasty;
  233.  
  234.   /*  If we haven't yet decided on which way to control shearing
  235.    *  decide using the maximum differential
  236.    */
  237.  
  238.   if (transform_core->trans_info[HORZ_OR_VERT] == ORIENTATION_UNKNOWN)
  239.     {
  240.       if (abs (diffx) > MIN_MOVE || abs (diffy) > MIN_MOVE)
  241.     {
  242.       if (abs (diffx) > abs (diffy))
  243.         {
  244.           transform_core->trans_info[HORZ_OR_VERT] = ORIENTATION_HORIZONTAL;
  245.           transform_core->trans_info[ORIENTATION_VERTICAL] = 0.0;
  246.         }
  247.       else
  248.         {
  249.           transform_core->trans_info[HORZ_OR_VERT] = ORIENTATION_VERTICAL;
  250.           transform_core->trans_info[ORIENTATION_HORIZONTAL] = 0.0;
  251.         }
  252.     }
  253.       /*  set the current coords to the last ones  */
  254.       else
  255.     {
  256.       transform_core->curx = transform_core->lastx;
  257.       transform_core->cury = transform_core->lasty;
  258.     }
  259.     }
  260.  
  261.   /*  if the direction is known, keep track of the magnitude  */
  262.   if (transform_core->trans_info[HORZ_OR_VERT] != ORIENTATION_UNKNOWN)
  263.     {
  264.       dir = transform_core->trans_info[HORZ_OR_VERT];
  265.       switch (transform_core->function)
  266.     {
  267.     case HANDLE_1:
  268.       if (dir == ORIENTATION_HORIZONTAL)
  269.         transform_core->trans_info[XSHEAR] -= diffx;
  270.       else
  271.         transform_core->trans_info[YSHEAR] -= diffy;
  272.       break;
  273.     case HANDLE_2:
  274.       if (dir == ORIENTATION_HORIZONTAL)
  275.         transform_core->trans_info[XSHEAR] -= diffx;
  276.       else
  277.         transform_core->trans_info[YSHEAR] += diffy;
  278.       break;
  279.     case HANDLE_3:
  280.       if (dir == ORIENTATION_HORIZONTAL)
  281.         transform_core->trans_info[XSHEAR] += diffx;
  282.       else
  283.         transform_core->trans_info[YSHEAR] -= diffy;
  284.       break;
  285.     case HANDLE_4:
  286.       if (dir == ORIENTATION_HORIZONTAL)
  287.         transform_core->trans_info[XSHEAR] += diffx;
  288.       else
  289.         transform_core->trans_info[YSHEAR] += diffy;
  290.       break;
  291.     default:
  292.       break;
  293.     }
  294.     }
  295. }
  296.  
  297. static void
  298. shear_tool_recalc (Tool *tool,
  299.            void *gdisp_ptr)
  300. {
  301.   TransformCore *transform_core;
  302.   GDisplay      *gdisp;
  303.   gfloat         width, height;
  304.   gfloat         cx, cy;
  305.  
  306.   gdisp = (GDisplay *) tool->gdisp_ptr;
  307.   transform_core = (TransformCore *) tool->private;
  308.  
  309.   cx = (transform_core->x1 + transform_core->x2) / 2.0;
  310.   cy = (transform_core->y1 + transform_core->y2) / 2.0;
  311.  
  312.   width = transform_core->x2 - transform_core->x1;
  313.   height = transform_core->y2 - transform_core->y1;
  314.  
  315.   if (width == 0)
  316.     width = 1;
  317.   if (height == 0)
  318.     height = 1;
  319.  
  320.   /*  assemble the transformation matrix  */
  321.   gimp_matrix3_identity  (transform_core->transform);
  322.   gimp_matrix3_translate (transform_core->transform, -cx, -cy);
  323.  
  324.   /*  shear matrix  */
  325.   if (transform_core->trans_info[HORZ_OR_VERT] == ORIENTATION_HORIZONTAL)
  326.     gimp_matrix3_xshear (transform_core->transform,
  327.              (float) transform_core->trans_info [XSHEAR] / height);
  328.   else
  329.     gimp_matrix3_yshear (transform_core->transform,
  330.              (float) transform_core->trans_info [YSHEAR] / width);
  331.  
  332.   gimp_matrix3_translate (transform_core->transform, +cx, +cy);
  333.  
  334.   /*  transform the bounding box  */
  335.   transform_core_transform_bounding_box (tool);
  336.  
  337.   /*  update the information dialog  */
  338.   shear_info_update (tool);
  339. }
  340.  
  341. TileManager *
  342. shear_tool_shear (GimpImage    *gimage,
  343.           GimpDrawable *drawable,
  344.           GDisplay     *gdisp,
  345.           TileManager  *float_tiles,
  346.           gboolean      interpolation,
  347.           GimpMatrix3   matrix)
  348. {
  349.   gimp_progress *progress;
  350.   TileManager   *ret;
  351.  
  352.   progress = progress_start (gdisp, _("Shearing..."), FALSE, NULL, NULL);
  353.  
  354.   ret = transform_core_do (gimage, drawable, float_tiles,
  355.                interpolation, matrix,
  356.                progress ? progress_update_and_flush :
  357.                (progress_func_t) NULL,
  358.                progress);
  359.  
  360.   if (progress)
  361.     progress_end (progress);
  362.  
  363.   return ret;
  364. }
  365.